#include "xvideoview.h"
#include "xsdl.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
}
#include <thread>
#include <iostream>
void MSleep(unsigned int ms)
{
    auto beg = clock();
    for(int i = 0; i < ms; i++)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        if((clock() - beg) / (CLOCKS_PER_SEC / 1000)  > ms)
            break;
    }
}

//获取当前时间戳
long long NOwMs()
{
    return clock() / (CLOCKS_PER_SEC / 1000);
}

void saveYUV420Frame(AVFrame* frame, const std::string& filename) {
    std::ofstream outfile(filename, std::ios::binary);
    if (!outfile) {
        std::cerr << "无法创建文件: " << filename << std::endl;
        return;
    }

    // 写入 Y 分量
    for (int i = 0; i < frame->height; i++) {
        outfile.write(reinterpret_cast<const char*>(frame->data[0] + i * frame->linesize[0]),
                     frame->width);
    }

    // 写入 U 分量
    for (int i = 0; i < frame->height / 2; i++) {
        outfile.write(reinterpret_cast<const char*>(frame->data[1] + i * frame->linesize[1]),
                     frame->width / 2);
    }

    // 写入 V 分量
    for (int i = 0; i < frame->height / 2; i++) {
        outfile.write(reinterpret_cast<const char*>(frame->data[2] + i * frame->linesize[2]),
                     frame->width / 2);
    }

    outfile.close();
    std::cout << "YUV帧已保存: " << filename << std::endl;
}

XVideoView::XVideoView()
{

}

XVideoView* XVideoView::Create(RenderType type)
{
    switch (type)
    {
    case XVideoView::SDL :
        return new XSDL();
        break;
    default :
        break;
    }

    return nullptr;
}

void XVideoView::mirrorYUV420_Horizontal(unsigned char* yuv_data, int width, int height)
{
    if(!yuv_data)return;

    //先翻转Y
    unsigned char temp_date = 0;
    for(int y = 0; y < height; y++)
    {
        unsigned char * start_row = yuv_data + y * width;
        unsigned char * end_row = yuv_data + y * width + width - 1;
        for(; start_row < end_row;)
        {
            temp_date = *start_row;
            *start_row = *end_row;
            start_row++;
            *end_row = temp_date;
            end_row--;
        }
    }

    //翻转UV
    int uv_width = width / 2;
    int uv_height = height / 2;
    unsigned char* u_tempdate = yuv_data + width * height;
    for(int y = 0; y < uv_height; y++)
    {
        unsigned char * start_row = u_tempdate + y * uv_width;
        unsigned char * end_row = u_tempdate + y * uv_width + uv_width - 1;
        for(; start_row < end_row;)
        {
            temp_date = *start_row;
            *start_row = *end_row;
            start_row++;
            *end_row = temp_date;
            end_row--;
        }
    }


    unsigned char* v_tempdate = yuv_data + ((width * height) + (width * height) / 4);
    for(int y = 0; y < uv_height; y++)
    {
        unsigned char * start_row = v_tempdate + y * uv_width;
        unsigned char * end_row = v_tempdate + y * uv_width + uv_width - 1;
        for(; start_row < end_row;)
        {
            temp_date = *start_row;
            *start_row = *end_row;
            start_row++;
            *end_row = temp_date;
            end_row--;
        }
    }
}

bool XVideoView::Open(std::string filepath)
{
    if(ifs_.is_open())
    {
        ifs_.close();
    }
    ifs_.open(filepath, std::ios::binary);
    std::cout << "open file path " << filepath << std::endl;
    return ifs_.is_open();
}

AVFrame* XVideoView::Read()
{
    if(width_ <= 0 || height_ <= 0 || !ifs_)return NULL;
    //AVFrame已经申请，parame change free space
    if(frame_)
    {
        if(frame_->width != width_
              || frame_->height != height_
                || frame_->format != fmt_)
        {
            av_frame_free(&frame_);
        }
    }
    if(!frame_)
    {
        frame_ = av_frame_alloc();
        frame_->width = width_;
        frame_->height = height_;
        frame_->format = fmt_;
        frame_->linesize[0] = width_ * 4;
        if(frame_->format == AV_PIX_FMT_YUV420P)
        {
            frame_->linesize[0] = width_;
            frame_->linesize[1] = width_ / 2;
            frame_->linesize[2] = width_ / 2;
        }
        //生成AVFrame空间，使用默认对齐
        auto re = av_frame_get_buffer(frame_, 0);
        if(re != 0)
        {
            char buf[1024] = {0};
            av_frame_free(&frame_);
            return NULL;
        }
        if(frame_ == NULL)return NULL;

    }
         //读取一帧数据
    if(frame_->format == AV_PIX_FMT_YUV420P)
    {
        ifs_.read((char*)frame_->data[0], frame_->linesize[0] *  height_);
        ifs_.read((char*)frame_->data[1], frame_->linesize[1] * height_ /2);
        ifs_.read((char*)frame_->data[2], frame_->linesize[2] * height_ / 2);
    }
    else
    {
        ifs_.read((char*)frame_->data[0], frame_->linesize[0] *  height_);
    }
    static int flag = 0;
    if(!flag)
    {
        flag = 1;
       saveYUV420Frame(frame_, "frame_001.yuv");
    }

    if(ifs_.gcount() == 0)return NULL;
    return frame_;
}

bool XVideoView::DrawFrame(AVFrame* frame)
{

    if(!frame || !frame->data[0])return false;
    count_++;
    if(beg_ms_ <= 0)
    {
        beg_ms_ = clock();
    }
    else if((clock() - beg_ms_) / (CLOCKS_PER_SEC / 1000) >= 1000)
    {
        render_fps_ = count_;
        count_ = 0;
        beg_ms_ = clock();
    }
    switch (frame->format)
    {
        case AV_PIX_FMT_YUV420P:
            return Draw(frame->data[0], frame->linesize[0],
                    frame->data[1], frame->linesize[1],
                    frame->data[2], frame->linesize[2]);
        case AV_PIX_FMT_BGRA:
            return Draw(frame->data[0], frame->linesize[0]);
        case AV_PIX_FMT_ARGB:
            return Draw(frame->data[0], frame->linesize[0]);
        case AV_PIX_FMT_RGBA:
            return Draw(frame->data[0], frame->linesize[0]);

        default:
            break;
    }
    return false;
}










